package cn.mw.cmdb.config.MQTT;

import cn.mw.cmdb.config.MQTTProviderConfig;
import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.entity.UManageInitDataCabinetPortInfo;
import cn.mw.cmdb.entity.V6800InitDataInfo;
import cn.mw.cmdb.exception.WarnParamTitleException;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.UNumManageServiceImpl;
import cn.mw.microMonitorCommon.util.RedisUtils;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.mw.cmdb.service.impl.InstanceServiceImpl.tagUManageIdKey;
import static cn.mw.cmdb.util.ValConvertUtil.intValueConvert;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;
import static cn.mw.cmdb.viewProcessor.ModelViewCabinetProcess.*;
import static cn.mw.cmdb.viewProcessor.ModelViewUNumProcess.*;


/**
 * mqtt返回消息处理
 * V6800协议
 */
@Slf4j
public class MessageArrivedByV6800 implements MessageArrivedHandle {
    public static final String V6800Key = "V6800Upload/";
    public static final String V6800CommonKey = "V6800Upload/#";
    //
    private static final String HeartBeatKey = "/HeartBeat";
    private static final String InitKey = "/Init";
    private static final String HeartBeatReq = "heart_beat_req";
    private static final String UStateChangedNotifyKey = "u_state_changed_notify_req";
    private static final String DeviesInitReqKey = "devies_init_req";

    @Override
    public void messageManage(String topic, Object message) throws Exception {
        byte[] payload = (byte[]) message;
        String data = new String(payload);
        //心跳接口
        if (topic != null && topic.contains(HeartBeatKey)) {
            heartBeatStateSync(data);
        }
        //初始化数据
        if (topic != null && topic.contains(InitKey)) {
            getDeviceInitData(data);
        }

        //资产变更
        if (topic != null && topic.contains(LabelStateKey)) {
            deviceUNumCheck(topic, data);
        }

        log.info("MessageArrivedByV6800::format" + data);
    }

    public void heartBeatStateSync(String message) throws Exception {
        try {
            //V6800心跳包数据
            V6800HeartBeatParam v6800HeartBeatParam = JSONObject.parseObject(message, V6800HeartBeatParam.class);
            Set<String> moduleSnList = new HashSet<>();
            if (v6800HeartBeatParam != null && HeartBeatReq.equals(v6800HeartBeatParam.getMsg_type())) {
                String gatewayId = v6800HeartBeatParam.getModule_sn();
                List<V6800HeartBeatUManageParam> dataList = v6800HeartBeatParam.getData();
                if (CollectionUtils.isNotEmpty(dataList)) {
                    for (V6800HeartBeatUManageParam beatParam : dataList) {
                        moduleSnList.add(beatParam.getModule_sn());
                    }
                }
                //同步机柜在线状态
                setRedisUMangeKey(gatewayId,moduleSnList);
            }
        } catch (Exception e) {
            log.error("V6800heartBeatStateSync to fail::", e);
        }

    }

    /**
     * 根据获取的变更信息，匹配数据库中的设备U位信息是否正确
     * 同时根据匹配结果，设置上传机柜U位指示灯
     */
    public void deviceUNumCheck(String topic, String data) throws Exception {
        if (!Strings.isNullOrEmpty(data)) {
            V6800LabelStateParam labelStateParam = JSONObject.parseObject(data, V6800LabelStateParam.class);
            //网关ID
            String gatewaySn = labelStateParam.getGateway_sn();
            String msgType = labelStateParam.getMsg_type();
            List<Stream<String>> collect = labelStateParam.getData().stream().map(s -> s.getU_data().stream().map(t -> t.getTag_code())).collect(Collectors.toList());

            List<MwCabinetLayoutDataBaseParam> cabinetUNumStateList = new ArrayList<>();

            V6800SetUIndexColorParam colorParam = new V6800SetUIndexColorParam();
            colorParam.setGateway_sn(gatewaySn);
            //错误实例数据
            List<InstanceInfo> failList = new ArrayList<>();
            //资产状态变更
            if (UStateChangedNotifyKey.equals(msgType)) {
                List<V6800LabelStateDataParam> stateDataList = labelStateParam.getData();

                List<String> tagCodeList = stateDataList.stream().flatMap(t -> t.getU_data().stream()).map(V6800LabelStateUModuleParam::getTag_code).distinct().collect(Collectors.toList());

                CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
                InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
                //获取标签Id对应的实例设备
                List<InstanceInfo> instanceInfoList = instanceService.doListByTagIdsNotAuth(tagCodeList);
                Map<Object, InstanceInfo> tagByUIndexMap = instanceInfoList.stream().filter(s -> s.getData() != null).collect(Collectors.toMap(s -> s.getData().get(tagUManageIdKey), s -> s, (
                        value1, value2) -> {
                    return value2;
                }));

                List<V6800SetUIndexColorJsonParam> colorJsonList = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(stateDataList)) {
                    for (V6800LabelStateDataParam stateDataParam : stateDataList) {
                        V6800SetUIndexColorJsonParam colorJsonParam = new V6800SetUIndexColorJsonParam();

                        //U位监测模块Id
                        String extendoMduleSn = stateDataParam.getExtend_module_sn();
                        //AIoT网关传感器接口编号
                        int portIndex = stateDataParam.getHost_gateway_port_index();
                        colorJsonParam.setExtend_module_sn(extendoMduleSn);
                        colorJsonParam.setHost_gateway_port_index(portIndex);

                        List<V6800LabelStateUModuleParam> uData = stateDataParam.getU_data();


                        List<V6800SetUIndexColorDataListParam> colorDataList = new ArrayList<>();

                        if (CollectionUtils.isNotEmpty(uData)) {
                            for (V6800LabelStateUModuleParam uModuleParam : uData) {
                                V6800SetUIndexColorDataListParam colorDataListParam = new V6800SetUIndexColorDataListParam();

                                MwCabinetLayoutDataBaseParam cabinetUNumState = new MwCabinetLayoutDataBaseParam();
                                //发生变化的 U 位序号
                                int uIndex = uModuleParam.getU_index();
                                cabinetUNumState.setIndex(uIndex);
                                colorDataListParam.setU_index(uIndex);
                                //U位资产标签Id
                                String tagCode = uModuleParam.getTag_code();
                                int newState = uModuleParam.getNew_state();
                                int oldState = uModuleParam.getOld_state();
                                //占用状态4 绿色
                                InstanceInfo instanceInfo = tagByUIndexMap.get(tagCode);
                                //上架标识
                                if (newState == 1 && oldState == 0) {
                                    int uNum = intValueConvert(instanceInfo.getData().get(deviceUIndex));
                                    if (uIndex == uNum) {
                                        //上架正确
                                        cabinetUNumState.setStatus(UIndexUsedOKState);
                                        colorDataListParam.setColor_code(UIndexUsedOKState);
                                    } else {
                                        //上架错误
                                        cabinetUNumState.setStatus(UIndexUsedFailState);
                                        colorDataListParam.setColor_code(UIndexUsedFailState);
                                        failList.add(instanceInfo);
                                    }
                                }
                                //下架标识
                                if (newState == 0 && oldState == 1) {
                                    //占用状态4 绿色
                                    int uNum = intValueConvert(tagByUIndexMap.get(tagCode));
                                    if (uIndex != uNum) {
                                        //下架正确
                                        cabinetUNumState.setStatus(UIndexFreeState);
                                        colorDataListParam.setColor_code(UIndexFreeState);
                                    } else {
                                        //下架错误
                                        cabinetUNumState.setStatus(UIndexUsedFailState);
                                        colorDataListParam.setColor_code(UIndexUsedFailState);
                                        failList.add(instanceInfo);
                                    }
                                }
                                cabinetUNumStateList.add(cabinetUNumState);
                                colorDataList.add(colorDataListParam);
                            }
                        }
                        colorJsonParam.setU_color_data(colorDataList);
                        colorJsonList.add(colorJsonParam);
                    }
                }
                colorParam.setData(colorJsonList);

                //发布消息，主动上传设置U位指示灯
                sendUManageLightState(gatewaySn, colorParam);
                if (CollectionUtils.isNotEmpty(failList)) {
                    //TODO U位管理错误时，需要通知提醒
                }
            }
        }
    }


    /**
     * 发送U位管理指示灯状态消息
     */
    public static void sendUManageLightState(String gatewaySn, Object sendInfo) {
        if (!Strings.isNullOrEmpty(gatewaySn)) {
            //发布消息，主动上传设置U位指示灯
            try {
                MQTTProviderConfig mqttProviderConfig = SpringUtils.getBean(MQTTProviderConfig.class);
                //发布的主题
                String publishTopic = V6800Key + gatewaySn;
                //发布消息
                if (null != sendInfo) {
                    String publishData = JSONObject.toJSONString(sendInfo);
                    log.info("sendUManageLightState::publishData:" + publishData);
                    mqttProviderConfig.publish(publishTopic, publishData);
                }
            } catch (Exception e) {
                throw new WarnParamTitleException("send_light_state_error", gatewaySn);
            }
        }
    }

    /**
     * 获取设备初始化数据
     */
    private void getDeviceInitData(String data) throws Exception {
        V6800InitDataInfo v6800InitDataInfo = new V6800InitDataInfo();
        if (!Strings.isNullOrEmpty(data)) {
            V6800DeviceInitInfoParam deviceInitInfoParam = JSONObject.parseObject(data, V6800DeviceInitInfoParam.class);
            //网关ID
            String gatewaySn = deviceInitInfoParam.getGateway_sn();
            String msgType = deviceInitInfoParam.getMsg_type();
            String gatewayIp = deviceInitInfoParam.getGateway_ip();
            v6800InitDataInfo.setGatewaySn(gatewaySn);
            v6800InitDataInfo.setGatewayIp(gatewayIp);
            List<UManageInitDataCabinetPortInfo> relationCabinetInfoList = new ArrayList<>();
            //资产数据初始化
            if (DeviesInitReqKey.equals(msgType)) {
                UManageInitDataCabinetPortInfo cabinetPortInfo = new UManageInitDataCabinetPortInfo();
                List<V6800HeartBeatUManageParam> uManageData = deviceInitInfoParam.getData();
                for (V6800HeartBeatUManageParam uManageParam : uManageData) {
                    cabinetPortInfo.setModuleIndex(uManageParam.getModule_index());
                    cabinetPortInfo.setModuleSn(uManageParam.getModule_sn());
                    cabinetPortInfo.setModuleMNum(uManageParam.getModule_m_num());
                    cabinetPortInfo.setModuleUNum(uManageParam.getModule_u_num());
                    relationCabinetInfoList.add(cabinetPortInfo);
                }
                v6800InitDataInfo.setData(relationCabinetInfoList);
            }
            if (v6800InitDataInfo != null && !Strings.isNullOrEmpty(v6800InitDataInfo.getGatewaySn()) && !Strings.isNullOrEmpty(v6800InitDataInfo.getGatewayIp())) {
                CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
                UNumManageServiceImpl uNumManageService = (UNumManageServiceImpl) cmdbServiceManage.getModelService(UNumManageServiceImpl.ID);
                //初始化网关id，U位管理id，插入映射表中
                uNumManageService.syncDeviceInitData(v6800InitDataInfo);
            }

        }

    }


    /**
     * 上架设备设置预占用位置
     *
     * @param putOnDeviceList 上架设备
     */
    public void putOnDeviceSettingLightState(List<InstanceInfo> putOnDeviceList) throws Exception {
        //TODO 问题，上架设备对应的机柜怎么绑定网关ID
        //TODO AIoT 网关传感器接口编号
        //TODO  位监测模块 ID
        List<String> ids = new ArrayList<>();
        List<String> cabinetCodes = new ArrayList<>();
        Map<String, InstanceInfo> instanceMaps = new HashMap<>();
        //资产实例数据，服务器，交换机等
        if (CollectionUtils.isNotEmpty(putOnDeviceList)) {
            //所属机柜id分组下的实例数据
            Map<String, List<InstanceInfo>> relationCabinetIdMap = putOnDeviceList.stream().filter(s -> s.getData() != null && !Strings.isNullOrEmpty(strValueConvert(s.getData().get(relationCabinet)))).collect(Collectors.groupingBy(s -> strValueConvert(s.getData().get(relationCabinet))));
            ids = putOnDeviceList.stream().map(s -> s.getId()).collect(Collectors.toList());

            CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);

            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            //根据机柜id获取对应的机柜数据
            List<InstanceInfo> cabinetInfos = instanceService.doListByIdsNotAuth(ids);
            Map<String, String> cabinetRuleMapById = new HashMap<>();
            for (InstanceInfo cabinetInfo : cabinetInfos) {
                if (cabinetInfo.getData() != null) {
                    //获取机柜的编码
                    String cabinetCodeStr = strValueConvert(cabinetInfo.getData().get(cabinetCode));
                    cabinetCodes.add(cabinetCodeStr);
                    //呼获取机柜的占用规则
                    String ruleType = strValueConvert(cabinetInfo.getData().get(cabinetRuleType));
                    cabinetRuleMapById.put(cabinetInfo.getId(), ruleType);
                }
            }

            UNumManageServiceImpl uNumManageService = (UNumManageServiceImpl) cmdbServiceManage.getModelService(UNumManageServiceImpl.ID);
            QueryUNumCabinetRelationParam param = new QueryUNumCabinetRelationParam();
            param.setCabinetCodes(cabinetCodes);
            List<MwCabinetRelationUNumParam> uNumCabinetRelationInfos = uNumManageService.getUNumCabinetRelationInfos(param);
            //根据gatewaySn分组
            Map<String, List<MwCabinetRelationUNumParam>> MwCabinetRelationUNumMap = uNumCabinetRelationInfos.stream().filter(s -> !Strings.isNullOrEmpty(s.getGatewaySn())).collect(Collectors.groupingBy(s -> s.getGatewaySn()));

            // TODO 需要根据gatewaySn来设置U位的灯的信息，所有的信息按照gatewaySn来分类
            for (Map.Entry<String, List<MwCabinetRelationUNumParam>> entry : MwCabinetRelationUNumMap.entrySet()) {
                //每个gatewaySn作为一次请求
                String gatewaySn = entry.getKey();
                List<MwCabinetRelationUNumParam> listInfos = entry.getValue();
                V6800SetUIndexColorParam colorParam = new V6800SetUIndexColorParam();
                colorParam.setGateway_sn(gatewaySn);
                List<V6800SetUIndexColorJsonParam> indexColorList = new ArrayList<>();

                //U位数据整理
                for (MwCabinetRelationUNumParam relationUNumParam : listInfos) {
                    V6800SetUIndexColorJsonParam colorJsonParam = new V6800SetUIndexColorJsonParam();
                    colorJsonParam.setExtend_module_sn(relationUNumParam.getModuleSn());
                    colorJsonParam.setHost_gateway_port_index(relationUNumParam.getModuleIndex());
                    //获取对应的机柜id
                    String instanceId = relationUNumParam.getInstanceId();
                    if (instanceMaps != null && relationCabinetIdMap.containsKey(instanceId)) {
                        List<InstanceInfo> instanceInfoList = relationCabinetIdMap.get(instanceId);
                        List<V6800SetUIndexColorDataListParam> u_color_data = new ArrayList<>();
                        for (InstanceInfo instanceInfo : instanceInfoList) {
                            V6800SetUIndexColorDataListParam colorDataListParam = new V6800SetUIndexColorDataListParam();
                            String ruleType = cabinetRuleTypeUpKey;
                            if (instanceInfo.getData() != null) {
                                String relationCabinetId = strValueConvert(instanceInfo.getData().get(relationCabinet));
                                if (cabinetRuleMapById != null && cabinetRuleMapById.containsKey(relationCabinetId)) {
                                    ruleType = cabinetRuleMapById.get(relationCabinetId);
                                }
                                if (instanceInfo.getData() != null) {
                                    Map<String, Object> data = instanceInfo.getData();
                                    //设备高度
                                    int UHeight = intValueConvert(data.get(deviceHeight)) == 0 ? 1 : intValueConvert(data.get(deviceHeight));
                                    //获取U位数
                                    int UNumEnd = 0;
                                    if (data.get(deviceUIndex) != null) {
                                        //获取下属设备U位
                                        int UNumStart = intValueConvert(data.get(deviceUIndex));
                                        colorDataListParam.setU_index(UNumStart);
                                        colorDataListParam.setColor_code(UIndexReservedUsedState);
                                    }
                                }
                            }
                            u_color_data.add(colorDataListParam);
                        }
                        colorJsonParam.setU_color_data(u_color_data);
                    }
                    indexColorList.add(colorJsonParam);
                }
                colorParam.setData(indexColorList);
                //设置上架指示灯
                sendUManageLightState(gatewaySn, colorParam);
            }

        }

    }

    /**
     * 下架设备设置预释放位置
     *
     * @param putDownDeviceList 下架设备
     */
    public void putDownDeviceSettingLightState(List<InstanceInfo> putDownDeviceList) {


    }

}
